package org.infodavid.common.ejb;

import java.util.HashMap;
import java.util.Map;

import javax.ejb.Local;
import javax.ejb.PrePassivate;
import javax.persistence.CollectionTable;
import javax.persistence.Column;
import javax.persistence.ElementCollection;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.MapKeyColumn;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.PrePersist;
import javax.persistence.PreUpdate;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;
import javax.persistence.Version;

import org.hibernate.annotations.ForeignKey;
import org.hibernate.annotations.Index;
import org.hibernate.annotations.OptimisticLockType;
import org.hibernate.annotations.Persister;
import org.hibernate.annotations.Target;
import org.hibernate.annotations.Type;
import org.joda.time.DateTime;

import org.infodavid.common.impl.model.UserSessionImpl;
import org.infodavid.common.model.IUser;
import org.infodavid.common.model.IUserSession;
import org.infodavid.common.model.impl.persisters.VersionSafeSingleTableEntityPersister;
import org.infodavid.common.persistence.INamed;
import org.infodavid.common.persistence.UserSessionDataService;

/**
 * The Class UserSessionBean.
 */
@Entity(name = "IUserSession")
@org.hibernate.annotations.Entity(dynamicUpdate = true, selectBeforeUpdate = true, dynamicInsert = true, optimisticLock = OptimisticLockType.NONE)
@Persister(impl = VersionSafeSingleTableEntityPersister.class)
@Table(name = "USER_SESSIONS")
@NamedQueries(value = {
    @NamedQuery(name = UserSessionDataService.QUERY_FIND_COUNT, query = "select count(d."
        + IUserSession.KEY + ") from IUserSession d"),
    @NamedQuery(name = UserSessionDataService.QUERY_FIND, query = "select d from IUserSession d"),
    @NamedQuery(name = UserSessionDataService.QUERY_FIND_ACTIVE_COUNT, query = "select count(d."
        + IUserSession.KEY + ") from IUserSession d where d.archived = 0"),
    @NamedQuery(name = UserSessionDataService.QUERY_FIND_ACTIVE, query = "select d from IUserSession d where d.archived = 0"),
    @NamedQuery(name = UserSessionDataService.QUERY_FIND_BY_CREATION_DATE, query = "select d from IUserSession d where d.archived = 0 and d."
        + IUserSession.CREATION_DATE + " between :date1 and :date2"),
    @NamedQuery(name = UserSessionDataService.QUERY_FIND_BY_CREATION_DATE_COUNT, query = "select count(d."
        + IUserSession.KEY
        + ") from IUserSession d where d.archived = 0 and d."
        + IUserSession.CREATION_DATE + " between :date1 and :date2"),
    @NamedQuery(name = UserSessionDataService.QUERY_FIND_BY_MODIFICATION_DATE, query = "select d from IUserSession d where d.archived = 0 and d."
        + IUserSession.MODIFICATION_DATE + " between :date1 and :date2"),
    @NamedQuery(name = UserSessionDataService.QUERY_FIND_BY_MODIFICATION_DATE_COUNT, query = "select count(d."
        + IUserSession.KEY
        + ") from IUserSession d where d.archived = 0 and d."
        + IUserSession.MODIFICATION_DATE + " between :date1 and :date2"),
    @NamedQuery(name = UserSessionDataService.QUERY_FIND_LAST_ACTIVE_BY_USER, query = "select d from IUserSession d where d.archived = 0 and d."
        + IUserSession.USER
        + '.'
        + IUser.KEY
        + " = :"
        + IUser.ID
        + " and d."
        + IUserSession.SIGNED_OUT
        + " = 0 and d."
        + IUserSession.LAST_ACCESS_DATE
        + " = (select max(d."
        + IUserSession.LAST_ACCESS_DATE
        + ") from IUserSession d where d.archived = 0 and d."
        + IUserSession.USER
        + '.'
        + IUser.KEY
        + " = :" + IUser.ID + " and d." + IUserSession.LAST_ACCESS_DATE + " > :date1)")
})
@Local(value = IUserSession.class)
public class UserSessionBean extends UserSessionImpl {

	/** The Constant serialVersionUID. */
	private static final long serialVersionUID = 1660345027625851665L;

	/**
	 * The Constructor.
	 * @throws Exception the exception
	 */
	protected UserSessionBean() throws Exception {
		super();
	}

	/**
	 * The Constructor.
	 * @param keyArg the key arg
	 * @throws Exception the exception
	 */
	protected UserSessionBean(final String keyArg) throws Exception {
		super(keyArg);
	}

	/*
	 * (non-Javadoc)
	 * @see org.infodavid.common.impl.model.UserImpl#init()
	 */
	@Override
	@PrePassivate
	public void init() throws Exception {
		super.init();
	}

	/*
	 * (non-Javadoc)
	 * @see org.infodavid.common.impl.model.DataObjectImpl#getCreationDate()
	 */
	@Override
	@Column(name = CREATION_DATE, nullable = false, updatable = false)
	@Type(type = "org.infodavid.persistence.impl.hibernate.usertype.DateTimeUserType")
	@Index(name = "IDX_USER_SESSIONS_CREATIONDATE")
	public DateTime getCreationDate() {
		return super.getCreationDate();
	}

	/*
	 * (non-Javadoc)
	 * @see org.infodavid.common.impl.model.DataObjectImpl#getModificationDate()
	 */
	@Override
	@Version
	@Column(name = MODIFICATION_DATE, nullable = false)
	@Type(type = "org.infodavid.persistence.impl.hibernate.usertype.DateTimeUserType")
	public DateTime getModificationDate() {
		return super.getModificationDate();
	}

	/*
	 * (non-Javadoc)
	 * @see org.infodavid.common.impl.model.DataObjectImpl#getKey()
	 */
	@Override
	@Id
	@Column(name = ID, nullable = false, length = 36, updatable = false)
	public String getKey() {
		return super.getKey();
	}

	/*
	 * (non-Javadoc)
	 * @see org.infodavid.common.impl.model.DataObjectImpl#isArchived()
	 */
	@Override
	@Column(name = ARCHIVED, nullable = false)
	@Index(name = "IDX_USER_SESSIONS_ARCHIVED")
	public boolean isArchived() {
		return super.isArchived();
	}

	/*
	 * (non-Javadoc)
	 * @see org.infodavid.common.impl.model.UserSessionImpl#isSignedOut()
	 */
	@Override
	@Column(name = SIGNED_OUT, nullable = false)
	@Index(name = "IDX_USER_SESSIONS_SIGNED_OUT")
	public boolean isSignedOut() {
		return super.isSignedOut();
	}

	/*
	 * (non-Javadoc)
	 * @see org.infodavid.common.impl.model.UserSessionImpl#getAccessesCount()
	 */
	@Override
	@Column(name = ACCESSES_COUNT, nullable = false)
	public long getAccessesCount() {
		return super.getAccessesCount();
	}

	/*
	 * (non-Javadoc)
	 * @see org.infodavid.common.impl.model.UserSessionImpl#getLastConnectionDate()
	 */
	@Override
	@Column(name = LAST_ACCESS_DATE, nullable = false)
	@Type(type = "org.infodavid.persistence.impl.hibernate.usertype.DateTimeUserType")
	@Index(name = "IDX_USER_SESSIONS_LAST_ACCESS")
	public DateTime getLastAccessDate() {
		return super.getLastAccessDate();
	}

	/*
	 * (non-Javadoc)
	 * @see org.infodavid.common.impl.model.UserSessionImpl#getLastIP()
	 */
	@Override
	@Column(name = LAST_IP, length = 15, nullable = true)
	public String getLastIP() {
		return super.getLastIP();
	}

	/*
	 * (non-Javadoc)
	 * @see org.infodavid.common.impl.model.UserSessionImpl#getUser()
	 */
	@Override
	@JoinColumn(name = IUser.ID, referencedColumnName = IUser.ID, nullable = false, updatable = false)
	@ManyToOne(targetEntity = UserBean.class, fetch = FetchType.LAZY)
	@ForeignKey(name = "FK_USER_SESSIONS_USER")
	public IUser getUser() {
		return super.getUser();
	}

	/*
	 * (non-Javadoc)
	 * @see org.infodavid.common.impl.model.UserSessionImpl#getProperties()
	 */
	@Override
	@ElementCollection(fetch = FetchType.LAZY)
	@CollectionTable(name = "USER_SESSIONS_PROPERTIES", joinColumns = @JoinColumn(name = ID, nullable = false), uniqueConstraints = @UniqueConstraint(name = "UC_USER_SESSIONS_PROPERTIES", columnNames = {
	    INamed.NAME, ID
	}))
	@MapKeyColumn(name = INamed.NAME, length = 32, nullable = false)
	@Column(name = "value", length = 512, nullable = true)
	@ForeignKey(name = "FK_USER_SESSIONS_PROPERTIES")
	@Target(value = HashMap.class)
	public Map<String,String> getProperties() {
		return super.getProperties();
	}

	@PrePersist
	@PreUpdate
	protected void preStore() {
		String value;

		for (final Map.Entry<String,String> entry : getProperties().entrySet()) {
			value = entry.getValue();

			if (value != null && value.length() > 512) {
				entry.setValue(value.substring(0, 511));
			}
		}
	}
}
